package edu.chl.dat255.bluebanana.utils;

import java.util.LinkedList;

/**
 * @author Pelle Evensen
 * Modified by Blue Banana
 */
public class ObservableAdapter implements Observable {

	private LinkedList<Observer> observers;
	private Observable parent;
	private boolean hasChanged;

	/**
	 * 
	 * @param parent
	 */
	public ObservableAdapter() {
		this(null);
	}

	/**
	 * 
	 * @param parent
	 */
	public ObservableAdapter(final Observable parent) {
		this.observers = new LinkedList<Observer>();
		if (parent != null) {
			this.parent = parent;
		} else {
			this.parent = this;
		}
		this.hasChanged = false;
	}

	@Override
	public final boolean addObserver(final Observer o) {
		if (!this.observers.contains(o)) {
			this.observers.add(o);
			return true;
		}

		return false;
	}

	public void clearChanged() {
		synchronized (this.observers) {
			this.hasChanged = false;
		}
	}

	@Override
	public final boolean deleteObserver(final Observer o) {
		return this.observers.remove(o);
	}

	@Override
	public final void deleteObservers() {
		this.observers.clear();
	}

	@Override
	public final boolean hasChanged() {
		return this.hasChanged;
	}

	@Override
	/**
	 * @inheritdoc
	 */
	public final void notifyObservers(final Object state) {
		synchronized (this.observers) {
			if (this.hasChanged) {
				for (Observer observer : this.observers) {
					observer.update(this.parent, state);
				}
			}
			clearChanged();
		}
	}

	public void setChanged() {
		synchronized (this.observers) {
			this.hasChanged = true;
		}
	}

	@Override
	public String toString() {
		if (this.parent == this) {
			return "ObservableAdapter [hasChanged=" + this.hasChanged
					+ ", observers=" + this.observers + ", parent=SELF ("
					+ this.getClass() + "]";
		}
		return "ObservableAdapter [hasChanged=" + this.hasChanged
				+ ", observers=" + this.observers + ", parent=" + this.parent
				+ "]";
	}

}
